//上传的原始函数定义
#include"PublicPupFile.h"
#if USE_PUBLIC_PUPFILE
#include"PublicTool.h"
#include"PublicNetHead.h"
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <string>

#if USE_SEND_FILE
#include <sys/sendfile.h>
#endif
//协议包头
typedef struct _PROTOCOL_HEADER{
//协议包标识,为"ana"
unsigned char signature[3];
/*协议包类型
0:普通文件传输,1:XML内容上报
*/
unsigned char contenttype;
//协议包内容长度
unsigned char contentlen[2];
}PROTOCOL_HEADER;
//static const int TCP_BUFSZ = 70*1024; //70K
#define TCP_BUFSZ 71680
#define SIGNATURE "ana"
#define FILE_UP 0
#define XML_UP 1
//#include<syslog.h>
//登录目标机器
int PupFile::plogin(const char* strip,int port,const char* user,const char*passwd){
#if USE_PUBLIC_SOCKET
	int ret=m_sock.Connect(strip,port,10000);
	if(ret<0)return -1;
	char buff[1024]={0};
	sprintf(buff,"LOGIN:%s;%s\r\n",user,passwd);
	if(m_sock.SendTCP(buff,strlen(buff),5000)<0){
		printf("plogin Write Socket Data Error.\n");
		m_sock.CloseSocket();
		return -1;
	}
	ret = read_line(buff,1024,10000);
	if( ret<=0 ){
		printf("plogin Get Response Error[%d].\n", ret);
		m_sock.CloseSocket();
		return -1;
	}
	return 1;
#else	
	int fd = -1;
	fd =  simple_connect( strip, port, 10);//创建到strip的socket的connect链接
	if( fd < 0){
		printf("plogin Cannot connect [%s:%d]\n",strip, port );
		return -1;
	}
	char buf[1024];
	sprintf(buf,"LOGIN:%s;%s\r\n",user,passwd);
	int r = write_complete(fd, buf,strlen(buf), 25);
	if( r<= 0){
		printf("plogin Write Socket Data Error.\n");
		close(fd);
		return -1;
	}
	r = read_line(fd, buf, 1024, 30 );
	if( r<=0 ){
		close(fd);
		printf("plogin Get Response Error[%d].\n", r);
		return -1;
	}
	/////
	return fd;
#endif	
}

///filename中若出现@，转义成@A,若出现';'转义成@F, 
inline 
void PupFile::encode_filename(char* buf){
	char* ptr = buf;
	while(*ptr){
		register char c = *ptr;
		if( c=='@' || c==';'){
			char*  end = buf + strlen(buf);
			while(end > ptr){
				*(end+1) = *end;
				--end;
			}
			*ptr = '@';
			*(ptr+1) = ( c=='@'? 'A':'F');
			ptr = ptr +2;
		}
		else{
			++ptr;
		}
	}
}

//关闭
void PupFile::pbye(int fd){
#if USE_PUBLIC_SOCKET
	m_sock.CloseSocket();
#else	
	close(fd);
	fd = 0;
#endif	
}

//上传文件
int PupFile::pupfile(int fd, const char* rpath,const char* lpath,bool bAddIP){
	struct stat64 st;//创建stat64对象st来返回文件的属性信息（其实是文件大小）
	memset(&st,0,sizeof(st));
	if(stat64(lpath,&st)<0){//本地文件
		printf("pupfile Can't Get Fiile[%s] stat <%s>\n", lpath, strerror(errno) );
		return -5;
	}
	char buf[TCP_BUFSZ];
	if(bAddIP) {
#if USE_PUBLIC_SOCKET
		char ip[40]={0};
		if(m_sock.GetSocketName(ip)<0){
			printf("pupfile Can't Get Local socket info<getsockname() err>\n");
			return -6;
		}
		sprintf(buf,"%s-%s", ip,rpath);
#else		
		struct sockaddr_in addr;
		memset(&addr,0,sizeof(addr));
		socklen_t len = sizeof(struct sockaddr_in);
		if(getsockname(fd, (struct sockaddr*)&addr, (socklen_t *)&len) < 0){
			printf("pupfile Can't Get Local socket info<getsockname() err>\n");
			return -6;
		}
		sprintf(buf, "%s-%s", inet_ntoa(addr.sin_addr), rpath);
#endif		
		//printf("remote : %s\n", buf);
	}else {
		strcpy(buf, rpath);//远程文件
	}
	encode_filename( buf );//转意@和；
	sprintf(buf + strlen(buf),";" PRI64 "\r\n",st.st_size);//远程文件+本地文件的长度,比如：“a.txt;1024”
#if USE_PUBLIC_SOCKET
	int r = m_sock.SendTCP(buf,strlen(buf),5000);
#else	
	int r = write_complete( fd, buf,strlen(buf), 20 );//发送文件长度
#endif	
	if( r < 0 ){
		printf("pupfile Write Socket Data error[%s]\n", lpath);
		return -1;
	}
#if USE_PUBLIC_SOCKET
	r = read_line(buf,TCP_BUFSZ,10000);//接收远程机器反馈来的信息
#else	
	r = read_line(fd, buf, TCP_BUFSZ,  45 );//接收远程机器反馈来的信息
#endif	
	if(r<=0){
		printf("pupfile Read Socket Data error[%d][%s]\n", r, lpath);
		return -1;
	}
	if( buf[0] == '-'){//发送文件异常
		if(buf[9] == 'e')
			return -3;
		printf("REP: %s\n", buf);
		return -2;
	}
	///处理断点续传，pos记录下一次续传的正确位置
	int64_t pos = atoll( buf+ 4 );
	////
	int open_flag = O_RDONLY;
	int file = open( lpath, open_flag );//打开文件
	if(file < 0 ){
		printf("pupfile fopen [%s] err <%s>\n", lpath, strerror(errno) );
		return -1;
	}
#if USE_PUBLIC_SOCKET
	r=m_sock.SendFile(file,&pos,st.st_size-pos);
	if(r<0)return -1;
#else	
#if USE_SEND_FILE
	ssize_t sendsize=0;
	do{
		int status=0;
#if USE_SELECT_MODE		
		fd_set wrst;FD_ZERO(&wrst);FD_SET(fd,&wrst);
		struct timeval tmo;memset(&tmo,0,sizeof(tmo));tmo.tv_sec = timeout;
		status = select(fd +1,NULL,&wrst,NULL,timeout != 0 ? &tmo: NULL);
		if(status<1)return -1;
#else		
		struct pollfd ufds;
		ufds.fd = fd;ufds.events = POLLOUT;ufds.revents = 0;
		int ms = 5000;
		status = poll(&ufds,1,ms);
#endif		
		if(status==1){
			sendsize=sendfile64(fd,file,&pos,st.st_size-pos);
			//printf("sendsize2:%zd Pos:" PRI64 " Last:" PRI64 " errno:%d(%s)\n",sendsize,pos,st.st_size-pos,errno,strerror(errno));
		}else{
			printf("Send err\n");
			break;
		}
	}while(sendsize>0);
#else	
	int DATA_LEN = 128*1024;
	char* data_buf = (char*)malloc( DATA_LEN );
	if(!data_buf){
		printf("pupfile Not Enough Memory.\n");
		close(fd);
		return -1;
	}
	
	if( pos > 0){
		if(lseek64( file, pos, SEEK_SET ) < 0){//移动文件的读写位置
			printf("pupfile seek file[%s] err<%s>\n",lpath, strerror(errno) );
			close(file);
			free(data_buf);
			return -1;
		}
	}
	////开始上传文件
	while( true ){
		int read_len = read( file, data_buf, DATA_LEN );
		if( read_len < 0 ){
			printf("pupfile fread file[%s] err<%s>\n", lpath, strerror(errno));
			close(file);
			free(data_buf);
			return -1;
		}
		if( read_len <=0 )break;
		int data_pos = 0;

		while( data_pos < read_len ){
			int BLK = read_len-data_pos > 4096 ? 4096 : read_len-data_pos ;
			r = write_complete(fd, data_buf + data_pos , BLK , 45 );//发送文件
			if( r <= 0){
				printf("pupfile Write Socket err while send file [%s]\n",lpath);
				close(file);
				free(data_buf);
				return -1;
			}
			////
			data_pos += r;
		}
		//usleep(10000);
	}
	free(data_buf);
#endif	
#endif	
	close(file);
	///
#if USE_PUBLIC_SOCKET
	r = read_line(buf, TCP_BUFSZ, 30000 );//接收信息
#else	
	r = read_line( fd, buf, TCP_BUFSZ, 45 );//接收信息
#endif	
//	printf("%s\n", buf);
	if( r<=0 || buf[0] == '-'){
		printf("pupfile Upfile [%s] err[%d]<%s>\n", lpath, r, buf );
		return -2 ;
	}
	return 0;
}

#if 0
//上传文件
int PupFile::mypupfile(int fd, const char* rpath,const char* sendbuf,int64_t sendbuflen,bool bAddIP)
{
	if(sendbuf == NULL || sendbuflen <= 0)
		return -1;
	char buf[TCP_BUFSZ];
	if(bAddIP) {
		struct sockaddr_in addr;
		memset(&addr,0,sizeof(addr));
		socklen_t len = sizeof(struct sockaddr_in);
		if(getsockname(fd, (struct sockaddr*)&addr, (socklen_t *)&len) < 0)
		{
			printf("pupfile Can't Get Local socket info<getsockname() err>\n");
			return -6;
		}
		sprintf(buf, "%s-%s", inet_ntoa(addr.sin_addr), rpath);
		//printf("remote : %s\n", buf);
	}else {
		strcpy(buf, rpath);//远程文件
	}
	encode_filename( buf );//转意@和；

	sprintf(buf + strlen(buf) ,
		";%lld\r\n",
		 sendbuflen);//远程文件+本地文件的长度,比如：“a.txt;1024”
	//printf("#%s\n", buf);
	int r = write_complete( fd, buf,strlen(buf), 20 );//发送文件长度
	if( r <= 0 ){
		printf("pupfile Write Socket Data error\n");
		return -1;
	}
	r = read_line(fd, buf, TCP_BUFSZ,  45 );//接收远程机器反馈来的信息
	if( r<=0){
		printf("pupfile Read Socket Data error[%d]\n", r);
		return -1;
	}
	if( buf[0] == '-'){//发送文件异常
		if(buf[9] == 'e')
			return -3;
		printf("REP: %s\n", buf);
		return -2;
	}
	
	///处理断点续传，pos记录下一次续传的正确位置
	int64_t pos = atoll( buf+ 4 );
	//printf("pos = %lld\n", pos);
	///
	while( pos < sendbuflen ){
		int BLK = sendbuflen-pos > 4096 ? 4096 : sendbuflen-pos ;
		r = write_complete(fd, sendbuf + pos , BLK , 45 );//发送文件
		if( r <= 0){
			printf("pupfile Write Socket err while send file \n");
			//close(file);
			//free(data_buf);
			return -1;
		}
		////
		pos += r;
	}
#if 0
	int DATA_LEN = 128*1024;
	char* data_buf = (char*)malloc( DATA_LEN );
	if(!data_buf){
		printf("pupfile Not Enough Memory.\n");
		return -1;
	}
	////
	int open_flag = O_RDONLY;
	int file = open( lpath, open_flag );//打开文件
	if(file < 0 ){
		printf("pupfile fopen [%s] err <%s>\n", lpath, strerror(errno) );
		free(data_buf);
		return -1;
	}
	if( pos > 0){
		if(lseek64( file, pos, SEEK_SET ) < 0){//移动文件的读写位置
			printf("pupfile seek file[%s] err<%s>\n",lpath, strerror(errno) );
			close(file);
			free(data_buf);
			return -1;
		}
	}
	////开始上传文件
	while( true ){
		int read_len = read( file, data_buf, DATA_LEN );
		
		if( read_len < 0 ){
			printf("pupfile fread file[%s] err<%s>\n", lpath, strerror(errno));
			close(file);
			free(data_buf);
			return -1;
		}
		if( read_len <=0 )break;
		int data_pos = 0;

		while( data_pos < read_len ){
			int BLK = read_len-data_pos > 4096 ? 4096 : read_len-data_pos ;
			r = write_complete(fd, data_buf + data_pos , BLK , 45 );//发送文件
			if( r <= 0){
				printf("pupfile Write Socket err while send file [%s]\n",lpath);
				close(file);
				free(data_buf);
				return -1;
			}
			////
			data_pos += r;
		}
		usleep(10000);
	}
	///
	close(file);
	free(data_buf);
	///
#endif
	r = read_line( fd, buf, TCP_BUFSZ, 45 );//接收信息
//	printf("%s\n", buf);
	if( r<=0 || buf[0] == '-'){
		printf("pupfile Upfile err[%d]<%s>\n", r, buf );
		return -2 ;
	}
	
	return 0;
}

#endif

#if 0
//上传文件
int PupFile::pupxmlfile(int fd, char* sendbuf, int64_t sendbuflen, char *back)
{
	if(sendbuf == NULL || sendbuflen <= 0 || sendbuflen >= 65536 || back == NULL)
		return -1;
	char buf[TCP_BUFSZ];
	//协议包头
	PROTOCOL_HEADER header;
	memcpy(header.signature, SIGNATURE, 3);
	write_8(&header.contenttype, XML_UP);
	write_16(header.contentlen,sendbuflen);
	//拷贝到发送缓存
	memcpy(buf, &header, sizeof(PROTOCOL_HEADER));
	//拼接内容
	sprintf(buf+sizeof(PROTOCOL_HEADER), "%s", sendbuf);
	//从头开始发送
	int r = -1;
	int64_t pos = 0;
	//不能使用strlen(buf),因为包头中可能会因为所发内容长度小于256，导致contentlen的第一个字节为0
	//int64_t end = strlen(buf);
	int64_t end = sizeof(PROTOCOL_HEADER) + sendbuflen;
	while( pos < end ){
		int BLK = end-pos > 4096 ? 4096 : end-pos ;
		r = write_complete(fd, buf + pos , BLK , 20 );//发送文件
		if( r <= 0){
			printf("pupfile Write Socket err while send file \n");
			//close(file);
			//free(data_buf);
			return -1;
		}
		////
		pos += r;
	}
	r = read_line( fd, back, TCP_BUFSZ, 20 );//接收信息

	if( r<=0 || back[0] == '-'){
		printf("pupfile Upfile err[%d]<%s>\n", r, back );
		return -2 ;
	}

	return 0;
}

#endif

//建立连接
#if 0
int PupFile::simple_connect(const char* str_ip,int port,int timeout){
	int sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
	if( sock < 0)
		return -1;
	sockaddr_in addr;memset(&addr,0,sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	uint32_t ip = inet_addr(str_ip);//获得IP对应的整形
	if( ip ==  INADDR_NONE){//ip转换失败 则输入的str_ip为域名
#ifndef WIN32
		res_init(); //确保改变 /etc/resolv.conf能马上生效
#endif
		hostent* p= gethostbyname(str_ip);//参数为主机名或者域名
		if(!p){
			close(sock);
			return -1;
		}
		memcpy(&ip,(p->h_addr_list[0]),sizeof(uint32_t));
	}
	memcpy(&addr.sin_addr,&ip,sizeof(uint32_t));
#ifdef __MINGW32__
	unsigned long ul=0;
	ioctlsocket(sock,FIONBIO,(unsigned long *)&ul);  
#else	
	fcntl(sock,F_SETFL,fcntl(sock,F_GETFL) | O_NONBLOCK);//设置为非阻塞
	unsigned long arg = 1;
	ioctl(sock,FIONBIO,&arg);
#endif	
    struct linger so_linger={1,0};
    setsockopt(sock,SOL_SOCKET,SO_LINGER,(const char*)&so_linger,sizeof(struct linger));
	int r = connect(sock,(sockaddr*)&addr,sizeof(addr));
	if(r<0){
		if(errno != EINPROGRESS){
			close(sock);
			return -1;
		}		
#if USE_SELECT_MODE
		int status=0;
		fd_set wrst;FD_ZERO(&wrst);FD_SET(sock,&wrst);
		struct timeval tmo;memset(&tmo,0,sizeof(tmo));tmo.tv_sec = timeout;
		status = select(sock +1,NULL,&wrst,NULL,timeout != 0 ? &tmo: NULL);
		if(status<1){
			close(sock);
			return -1;
		}
#else		
		int status=0;
		pollfd ufds;ufds.fd = sock;
		ufds.events = POLLIN|POLLOUT; ufds.revents = 0;
		status = poll(&ufds,1,timeout * 1000 );
		if( status <= 0 ){
			close(sock);
			return -1;
		}
		if( ufds.revents & POLLERR || ufds.revents&POLLHUP){
			close(sock);
			return -1;
		}
#endif			
	}
	return sock;
}
#endif
#if USE_PUBLIC_SOCKET
int PupFile::read_line(char* buf,int len,int timeoutms){
	int sz = 0;
	while(sz < len){
		int ret=m_sock.RecvTCP(buf+sz,len-sz,timeoutms);
		if(ret<0){
			return -1;
		}else{
			sz += ret;
			buf[sz]='\0';
			char* str = strstr(buf,"\r\n");
			if(str){
				*str = '\0';
				return sz;
			}
		}
	}
	return sz;
}
#else
//发送
int PupFile::write_complete(int fd,const char* buf,int len,int timeout ){
	int sz = 0;
	while(sz < len){
		int status=0;
#if USE_SELECT_MODE		
		fd_set wrst;FD_ZERO(&wrst);FD_SET(fd,&wrst);
		struct timeval tmo;memset(&tmo,0,sizeof(tmo));tmo.tv_sec = timeout;
		status = select(fd +1,NULL,&wrst,NULL,timeout != 0 ? &tmo: NULL);
		if(status<1)return -1;
#else		
		struct pollfd ufds;
		ufds.fd = fd;ufds.events = POLLOUT;ufds.revents = 0;
		int ms = timeout != 0 ? timeout*1000:-1;
		status = poll(&ufds,1,ms);
#endif		
		if(status <= 0)
			return -1;
		int r = send(fd,buf + sz,len - sz,0);
		if (r <= 0)
			return -1;
		sz += r;
	}
	return sz;
}

//接收
int PupFile::read_line(int fd,char* buf,int len,int timeout){
	int sz = 0;
	while(sz < len-1 ){
#if USE_SELECT_MODE
		//多线程下存在问题
		fd_set wrst;FD_ZERO(&wrst);FD_SET(fd,&wrst);
		struct timeval tmo;memset(&tmo,0,sizeof(tmo));tmo.tv_sec = timeout;
		int status = select(fd +1,&wrst,NULL,NULL,timeout != 0 ? &tmo: NULL);
		if(status<1)return -1;	   
#else
		struct pollfd ufds;
		ufds.fd = fd;ufds.events = POLLIN;ufds.revents = 0;
		int ms = timeout>0 ? timeout*1000:1000;
		int status = poll(&ufds,1,ms);
		if(status<1)return -1;
#endif
		int r = recv(fd,buf + sz,len -1 - sz,0);//确保len长度全部读入
		if( r <= 0) {
			return -errno;
			//int e = errno;
			//if (e==EAGAIN || e==EWOULDBLOCK || e==EINTR)
			//	continue;
			//else
			//	return -e;
		}
		sz += r;
		buf[sz]='\0';
		char* str = strstr(buf,"\r\n");
		if(str){
			*str = '\0';
			return sz;
		}
	}
	return sz;
}
#endif

#if 0
//test pupxmlfile
int main(){
	PupFile up;
	//参数说明：1.目标地址 2.目标端口号 3.用户名 4.密码
	int fd = up.plogin("172.16.18.238", 10533, "dldeep", "dldeep");
	if(fd < 0)	{
		printf("登录服务器[172.16.18.238]失败!");
		return -2;
	}
	char res[TCP_BUFSZ];
	//参数说明：1.登录后得到的socket fd 2.发送的内容 3.发送内容的长度 4.返回的XML
	//int r = up.pupxmlfile(fd, "<?xml version='1.0' encoding='UTF-8' standalone='yes'?><ns2:COMMONDATA xmlns:ns2=\"com.dnion.easy.dto\"><ipArray>202.64.181.2</ipArray><ipArray>202.64.181.3</ipArray><version>1.1.29</version><upTime>12345</upTime><vTime>1398335353</vTime><heartbeat>1398325300</heartbeat><thresholdtime>1398322700</thresholdtime></ns2:COMMONDATA>", 329, res);
	int r = up.pupxmlfile(fd, "<ns2:COMMONDATA xmlns:ns2=\"com.dnion.easy.dto\"><function>heartbeat</function><paramlist><ip>101.64.181.2</ip><ip>101.64.181.3</ip><version>1.1.29</version><upTime>3557</upTime><vTime>1398335353</vTime><heartbeat>1398325353</heartbeat><thresholdtime>1398322797</thresholdtime></paramlist></ns2:COMMONDATA>", 304, res);
	//int r = up.pupxmlfile(fd, "<ns2:COMMONDATA xmlns:ns2=\"com.dnion.easy.dto\"><function>UpdateThreshold</function><paramlist><ip>101.64.181.2</ip><ip>101.64.181.3</ip><type>node</type></paramlist><information><time>1398322797</time><crcstring>1398322797</crcstring></information></ns2:COMMONDATA>", 267, res);
	//int r = up.pupxmlfile(fd, "<ns2:COMMONDATA xmlns:ns2=\"com.dnion.easy.dto\"><function>UpdateThreshold</function><paramlist><platformid>36</platformid><type>node</type></paramlist><information><time>1398322797</time><crcstring>1398322797</crcstring></information></ns2:COMMONDATA>", 250, res);
	if(r < 0)	{
		if(r == -3)		{
			printf("文件已存在\n");
			return 0;
		}
		up.pbye(fd);
		printf("上传失败");
		return -2;
	}
	up.pbye(fd);
	printf("%s\n", res);
	return 0;
}
#endif

#if 0
//test mypupfile
int main(){
	PupFile up;
	//参数说明：1.目标地址 2.目标端口号 3.用户名 4.密码
	int fd = up.plogin("172.16.18.238", 10533, "dldeep", "dldeep");
	if(fd < 0)	{
		printf("登录服务器[172.16.18.238]失败!");
		return -2;
	}
	//参数说明：1.登录后得到的socket fd 2.发送的文件明 3.发送的内容 4.发送内容的长度 5.是否需要在文件名中加入本机IP
	int r = up.mypupfile(fd, "123.txt", "i am 123.", 9, true);
	if(r < 0)	{
		if(r == -3) 		{
			printf("文件已存在\n");
			return 0;
		}
		up.pbye(fd);
		printf("上传失败");
		return -2;
	}
	up.pbye(fd);
	return 0;
}
#endif
#endif
